#include "signalfilter.h"
#include <QDebug>
#include <QMetaMethod>

SignalFilter::SignalFilter(QObject *parent) :
    QObject(parent)
{
    m_parameters[0] = 0;
}

void SignalFilter::connect(const Url &signal, QObject *reciever, const char *slot)
{
    int slotIdx = reciever->metaObject()->
            indexOfSlot(&slot[1]); // without 1 added by SLOT() macro
    if (slotIdx < 0) {
        qWarning() << "can't connect" << signal.toString() << "to" << slot <<
                      "slot didn't exist (forgot SLOT macro?)";
        return;
    }

    int signalIdx;
    QVector<int> parameterTypes;
    QMetaMethod slotMethod = reciever->metaObject()->method(slotIdx);
    for (int i = 0; i < slotMethod.parameterCount(); ++i)
        parameterTypes.push_back(slotMethod.parameterType(i));

    // check if empty filter exists
    if (m_emptyFilters.size() > 0) {
        signalIdx = m_emptyFilters[m_emptyFilters.size() - 1];
        m_emptyFilters.pop_back();
        filter_t &filter = m_filters[signalIdx];
        filter.signal = signal;
        filter.isEmpty = false;
        filter.reciever = reciever;
        filter.slot = slot;
        filter.parameterTypes = parameterTypes;
    } else {
        m_filters.append({signal, false, reciever, slot, parameterTypes});
        signalIdx = m_filters.size() - 1;
    }



    if (!QMetaObject::connect(this, signalIdx + metaObject()->methodCount(),
                              reciever, slotIdx)) {
        qWarning() << "can't connect" << signal.toString() << "to" << slot <<
                      "QMetaObject::connect failed";
    }

}

//void SignalFilter::disconnect(const Url &signal, QObject *reciever, const char *slot)
//{
//    for (int i = 0; i < m_filters.size(); ++i) {
//        const filter_t &filter = m_filters[i];
//        if (filter.signal == signal &&
//                filter.reciever == reciever &&
//                filter.slot == slot) {
//            int slotIdx = reciever->metaObject()->
//                    indexOfSlot(&slot[1]); // without 1 added by SLOT() macro
//            QMetaObject::disconnect(this, i + metaObject()->methodCount(),
//                                    reciever, slotIdx);
//            if (i == m_filters.size() - 1) {
//                m_filters.pop_front();
//            } else {
//                filter.isEmpty = true;
//                filter.reciever = 0;
//                filter.slot = 0;
//                m_emptyFilters.push_back(i);
//            }
//        }
//    }
//}

void SignalFilter::filter(const Url &signalUrl, QVariantList &parameters)
{
    qDebug() << "emitting" << signalUrl.toString();
    for (int i = 0; i < m_filters.size(); ++i) {
        const filter_t &filter = m_filters[i];

        if (filter.isEmpty)
            continue;

        if (filter.signal.match(signalUrl)) {
            if (parameters.count() != filter.parameterTypes.count()) {
                qWarning() << "parameters count mismatch:" << signalUrl.toString();
                return;
            }

            for (int i = 0; i < parameters.count(); ++i) {
                if (!parameters[i].convert(filter.parameterTypes[i])) {
                    qWarning() << "can't cast parameter" << i << signalUrl.toString();
                    return;
                }
                m_parameters[i + 1] = parameters[i].data();
            }


            QMetaObject::activate(this, metaObject(),
                                  i + metaObject()->methodCount(),
                                  m_parameters);
        }
    }
}

